// 支持 Spine 动画的 FGUI 发布检查工具
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');

class PublishedSpineChecker {
    constructor(publishPath) {
        this.publishPath = publishPath || "G:/uss/uss-art/svn/uss/fgui/publish";
        this.errors = [];
        this.warnings = [];
        this.info = [];
        this.oversizedAtlases = [];
        this.foundPackages = [];
        this.spineAnimations = [];
        
        // 创建logs目录
        this.logsDir = path.join(__dirname, '..', 'logs');
        if (!fs.existsSync(this.logsDir)) {
            fs.mkdirSync(this.logsDir, { recursive: true });
        }
        
        const timestamp = new Date().toISOString()
            .replace(/[:.]/g, '-')
            .replace('T', '_')
            .slice(0, -5);
        this.logFile = path.join(this.logsDir, `published-spine-check-${timestamp}.log`);
        
        console.log('🎯 FGUI 发布检查工具 (支持 Spine 动画)');
        console.log('======================================\n');
        console.log(`📁 发布目录: ${this.publishPath}`);
        console.log(`📁 日志文件: ${this.logFile}`);
    }

    // 日志记录
    log(message, type = 'info') {
        const logMessage = `${message}`;
        
        if (type === 'error') {
            console.error('❌ ' + message);
        } else if (type === 'warning') {
            console.log('⚠️  ' + message);
        } else if (type === 'success') {
            console.log('✅ ' + message);
        } else {
            console.log('🔍 ' + message);
        }
        
        fs.appendFileSync(this.logFile, logMessage + '\n', 'utf8');
    }

    // 验证发布目录结构
    validatePublishStructure() {
        this.log('验证发布目录结构...');
        
        if (!fs.existsSync(this.publishPath)) {
            this.errors.push(`发布目录不存在: ${this.publishPath}`);
            return false;
        }

        const files = fs.readdirSync(this.publishPath);
        this.log(`发布目录文件数量: ${files.length}`);
        
        if (files.length === 0) {
            this.errors.push('发布目录为空');
            return false;
        }

        // 分析所有文件类型
        const fileTypes = this.analyzeAllFileTypes(files);
        this.log(`文件类型分析: ${JSON.stringify(fileTypes)}`);

        return true;
    }

    // 分析所有文件类型（包括 Spine 动画文件）
    analyzeAllFileTypes(files) {
        const types = {
            // FGUI 标准文件
            xml: 0,
            bin: 0,
            // 图片文件
            png: 0,
            jpg: 0,
            jpeg: 0,
            // Spine 动画文件
            atlas: 0,
            json: 0,
            skel: 0,
            // 其他文件
            other: 0
        };

        files.forEach(file => {
            const ext = path.extname(file).toLowerCase();
            if (ext === '.xml') types.xml++;
            else if (ext === '.bin') types.bin++;
            else if (ext === '.png') types.png++;
            else if (ext === '.jpg') types.jpg++;
            else if (ext === '.jpeg') types.jpeg++;
            else if (ext === '.atlas') types.atlas++;
            else if (ext === '.json') types.json++;
            else if (ext === '.skel') types.skel++;
            else types.other++;
        });

        return types;
    }

    // 1. 智能识别包名（支持 Spine 动画）
    findPackagesIntelligently() {
        this.log('\n1. 智能识别包名（支持 Spine 动画）...');
        
        const files = fs.readdirSync(this.publishPath);
        const packages = new Set();

        // 策略1: 从 BIN 文件提取包名（主要来源）
        files.filter(f => f.endsWith('.bin')).forEach(file => {
            const pkgName = path.basename(file, '.bin');
            packages.add(pkgName);
            // this.log(`从BIN识别包: ${pkgName}`);
        });

        // 策略2: 从 XML 文件提取包名
        files.filter(f => f.endsWith('.xml') && !f.includes('atlas')).forEach(file => {
            const pkgName = path.basename(file, '.xml');
            packages.add(pkgName);
            this.log(`从XML识别包: ${pkgName}`);
        });

        // 策略3: 从图集文件提取包名
        files.filter(f => (f.includes('atlas') || f.includes('_a')) && 
                         (f.endsWith('.png') || f.endsWith('.jpg'))).forEach(file => {
            const pkgName = this.extractPackageNameFromAtlas(file);
            if (pkgName) {
                packages.add(pkgName);
                // this.log(`从图集识别包: ${pkgName} (来自 ${file})`);
            }
        });

        // 策略4: 从 Spine 动画文件提取包名
        files.filter(f => f.endsWith('.atlas') || f.endsWith('.json') || f.endsWith('.skel')).forEach(file => {
            const pkgName = this.extractPackageNameFromSpine(file);
            if (pkgName) {
                packages.add(pkgName);
                // this.log(`从Spine文件识别包: ${pkgName} (来自 ${file})`);
            }
        });

        this.foundPackages = Array.from(packages).sort();
        this.log(`智能识别到 ${this.foundPackages.length} 个包: ${this.foundPackages.join(', ')}`, 'success');
        
        return this.foundPackages;
    }

    // 从图集文件名提取包名
    extractPackageNameFromAtlas(filename) {
        // 常见图集命名模式:
        // package_atlas0.png, package_a0.png, atlas_package_0.png 等
        
        const patterns = [
            /^(.+)_atlas\d+\./,    // package_atlas0.png
            /^(.+)_a\d+\./,        // package_a0.png (简写)
            /^atlas_(.+)_\d+\./,   // atlas_package_0.png  
            /^atlas_(.+)\./,       // atlas_package.png
            /^(.+)\.(png|jpg)$/    // package.png (直接包名)
        ];

        for (const pattern of patterns) {
            const match = filename.match(pattern);
            if (match && match[1]) {
                return match[1];
            }
        }

        return null;
    }

    // 从 Spine 动画文件名提取包名
    extractPackageNameFromSpine(filename) {
        // Spine 文件命名模式:
        // animation.atlas, animation.json, animation.skel
        // package_animation.atlas 等
        
        const patterns = [
            /^(.+)\.(atlas|json|skel)$/,  // package.atlas
            /^(.+)_[^_]+\.(atlas|json|skel)$/ // package_animation.atlas
        ];

        for (const pattern of patterns) {
            const match = filename.match(pattern);
            if (match && match[1]) {
                return match[1];
            }
        }

        return null;
    }

    // 2. 检查图集情况
    checkAtlases() {
        this.log('\n2. 检查图集情况...');
        
        if (this.foundPackages.length === 0) {
            this.log('没有找到包，跳过图集检查', 'warning');
            return;
        }

        let totalAtlases = 0;
        let packagesWithManyAtlases = 0;

        this.foundPackages.forEach(pkg => {
            const atlasFiles = this.findPackageAtlasFiles(pkg);
            totalAtlases += atlasFiles.length;
            
            if (atlasFiles.length > 0) {
                this.log(`包 "${pkg}" 有 ${atlasFiles.length} 个图集`);
                
                // 检查图集尺寸
                const largeAtlases = [];
                atlasFiles.forEach(atlasFile => {
                    try {
                        const dimensions = this.getImageDimensions(atlasFile);
                        if (dimensions) {
                            const { width, height } = dimensions;
                            const size = `${width}x${height}`;
                            const fileSize = fs.statSync(atlasFile).size;
                            const sizeMB = (fileSize / (1024 * 1024)).toFixed(2);
                            
                            if (width > 2048 || height > 2048) {
                                this.warnings.push(`图集尺寸过大: ${pkg}/${path.basename(atlasFile)} (${size})`);
                                this.log(`  ❌ ${path.basename(atlasFile)}: ${size} (${sizeMB}MB)`, 'warning');
                            } else {
                                this.log(`  ✅ ${path.basename(atlasFile)}: ${size} (${sizeMB}MB)`);
                            }

                            largeAtlases.push({
                                filename: path.basename(atlasFile),
                                width: width,
                                height: height,
                                size: size,
                                fileSize: fileSize
                            });
                        }
                    } catch (error) {
                        this.errors.push(`无法分析图集: ${atlasFile}`);
                    }
                });

                // 检查图集数量
                if (atlasFiles.length > 2) {
                    packagesWithManyAtlases++;
                    this.oversizedAtlases.push({
                        package: pkg,
                        atlasCount: atlasFiles.length,
                        allAtlases: largeAtlases
                    });
                    this.warnings.push(`包 "${pkg}" 有 ${atlasFiles.length} 个图集，建议优化`);
                }
            } else {
                this.log(`包 "${pkg}" 没有图集文件`, 'info');
            }
        });

        this.log(`总计发现 ${totalAtlases} 个图集文件`);
        if (packagesWithManyAtlases > 0) {
            this.log(`有 ${packagesWithManyAtlases} 个包的图集数量超过2个`, 'warning');
        } else {
            this.log('图集数量检查通过', 'success');
        }
    }

    // 3. 检查 Spine 动画文件
    checkSpineAnimations() {
        this.log('\n3. 检查 Spine 动画文件...');
        
        const files = fs.readdirSync(this.publishPath);
        const spineFiles = files.filter(f => f.endsWith('.atlas') || f.endsWith('.json') || f.endsWith('.skel'));
        
        if (spineFiles.length === 0) {
            this.log('未找到 Spine 动画文件', 'info');
            return;
        }

        this.log(`发现 ${spineFiles.length} 个 Spine 相关文件`);

        // 按动画名称分组
        const animations = this.groupSpineFiles(spineFiles);
        
        Object.keys(animations).forEach(animName => {
            const animFiles = animations[animName];
            this.log(`动画 "${animName}": ${animFiles.map(f => path.extname(f)).join(', ')}`);
            
            // 检查 Spine 文件完整性
            this.checkSpineFileIntegrity(animName, animFiles);
        });

        this.spineAnimations = animations;
    }

    // 按动画名称分组 Spine 文件
    groupSpineFiles(spineFiles) {
        const animations = {};
        
        spineFiles.forEach(file => {
            const basename = path.basename(file, path.extname(file));
            
            // 处理可能的命名模式: animation, package_animation
            let animName = basename;
            if (basename.includes('_')) {
                // 如果是 package_animation 格式，使用完整的 basename
                animName = basename;
            }
            
            if (!animations[animName]) {
                animations[animName] = [];
            }
            animations[animName].push(file);
        });
        
        return animations;
    }

    // 检查 Spine 文件完整性
    checkSpineFileIntegrity(animName, files) {
        const exts = files.map(f => path.extname(f));
        const hasAtlas = exts.includes('.atlas');
        const hasJson = exts.includes('.json');
        const hasSkel = exts.includes('.skel');
        
        // 基本完整性检查
        if (!hasAtlas) {
            this.warnings.push(`Spine动画缺少.atlas文件: ${animName}`);
        }
        
        if (!hasJson && !hasSkel) {
            this.warnings.push(`Spine动画缺少数据文件(.json或.skel): ${animName}`);
        }
        
        // 检查对应的纹理文件
        const textureFiles = this.findSpineTextureFiles(animName);
        if (textureFiles.length === 0) {
            this.warnings.push(`Spine动画缺少纹理文件: ${animName}`);
        } else {
            this.log(`  纹理文件: ${textureFiles.length} 个`);
            
            // 检查纹理文件尺寸
            textureFiles.forEach(textureFile => {
                try {
                    const dimensions = this.getImageDimensions(textureFile);
                    if (dimensions) {
                        const { width, height } = dimensions;
                        if (width > 2048 || height > 2048) {
                            this.warnings.push(`Spine纹理尺寸过大: ${animName}/${path.basename(textureFile)} (${width}x${height})`);
                        }
                    }
                } catch (error) {
                    // 忽略错误
                }
            });
        }
    }

    // 查找 Spine 动画的纹理文件
    findSpineTextureFiles(animName) {
        const files = fs.readdirSync(this.publishPath);
        const patterns = [
            `${animName}.png`,
            `${animName}.jpg`,
            `${animName}_*.png`,
            `${animName}*.png`
        ];

        const textureFiles = [];
        patterns.forEach(pattern => {
            const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$', 'i');
            const matches = files.filter(f => regex.test(f) && 
                (f.endsWith('.png') || f.endsWith('.jpg') || f.endsWith('.jpeg')));
            textureFiles.push(...matches.map(f => path.join(this.publishPath, f)));
        });

        return [...new Set(textureFiles)];
    }

    // 4. 检查文件完整性
    checkFileIntegrity() {
        this.log('\n4. 检查文件完整性...');
        
        const files = fs.readdirSync(this.publishPath);
        let integrityIssues = 0;

        // 检查 FGUI 包文件配对
        this.foundPackages.forEach(pkg => {
            const hasXML = files.includes(`${pkg}.xml`);
            const hasBIN = files.includes(`${pkg}.bin`);

            if (hasXML && !hasBIN) {
                this.warnings.push(`包 "${pkg}" 有 XML 文件但缺少 BIN 文件`);
                integrityIssues++;
            }
        });

        // 检查文件大小和可访问性
        files.forEach(file => {
            const filePath = path.join(this.publishPath, file);
            try {
                const stats = fs.statSync(filePath);
                if (stats.size === 0) {
                    this.errors.push(`空文件: ${file}`);
                    integrityIssues++;
                }
                
                // 检查大文件
                if (stats.size > 10 * 1024 * 1024) { // 10MB
                    const sizeMB = (stats.size / (1024 * 1024)).toFixed(1);
                    this.warnings.push(`大文件: ${file} (${sizeMB}MB)`);
                }
            } catch (error) {
                this.errors.push(`无法访问文件: ${file}`);
                integrityIssues++;
            }
        });

        if (integrityIssues === 0) {
            this.log('文件完整性检查通过', 'success');
        } else {
            this.log(`发现 ${integrityIssues} 个文件完整性问题`, 'warning');
        }
    }

    // 查找包的图集文件
    findPackageAtlasFiles(pkg) {
        const files = fs.readdirSync(this.publishPath);
        const atlasFiles = [];

        // 多种图集命名模式
        const patterns = [
            `${pkg}_atlas*.png`,
            `${pkg}_atlas*.jpg`,
            `${pkg}_a*.png`, // 简写模式
            `${pkg}_a*.jpg`,
            `atlas_${pkg}_*.png`,
            `atlas_${pkg}_*.jpg`,
            `${pkg}*.png`, // 宽松匹配
            `${pkg}*.jpg`
        ];

        patterns.forEach(pattern => {
            const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$', 'i');
            const matches = files.filter(f => regex.test(f) && 
                (f.endsWith('.png') || f.endsWith('.jpg') || f.endsWith('.jpeg')));
            atlasFiles.push(...matches.map(f => path.join(this.publishPath, f)));
        });

        // 去重
        return [...new Set(atlasFiles)];
    }

    // 获取图片尺寸
    getImageDimensions(imagePath) {
        try {
            // 方法1: 使用 ImageMagick
            try {
                const output = execSync(`magick identify -format "%wx%h" "${imagePath}"`, { 
                    encoding: 'utf8',
                    stdio: ['pipe', 'pipe', 'ignore']
                }).trim();
                
                const [width, height] = output.split('x').map(Number);
                if (width && height) {
                    return { width, height };
                }
            } catch (magickError) {
                // ImageMagick 不可用
            }

            // 方法2: 解析 PNG 文件头
            if (imagePath.toLowerCase().endsWith('.png')) {
                return this.getPNGDimensions(imagePath);
            }
            
            return null;
            
        } catch (error) {
            return null;
        }
    }

    // 解析 PNG 文件头
    getPNGDimensions(imagePath) {
        try {
            const buffer = fs.readFileSync(imagePath);
            if (buffer.readUInt32BE(0) === 0x89504E47 && 
                buffer.readUInt32BE(4) === 0x0D0A1A0A) {
                
                const width = buffer.readUInt32BE(16);
                const height = buffer.readUInt32BE(20);
                return { width, height };
            }
        } catch (error) {
            // 忽略错误
        }
        return null;
    }

    // 生成详细报告
    generateReport() {
        const reportContent = [];
        
        reportContent.push('='.repeat(70));
        reportContent.push('         FGUI 发布检查报告 (支持 Spine 动画)');
        reportContent.push('='.repeat(70));
        reportContent.push(`检查时间: ${new Date().toLocaleString()}`);
        reportContent.push(`发布目录: ${this.publishPath}`);
        reportContent.push(`日志文件: ${this.logFile}`);
        reportContent.push('');

        // 目录文件统计
        const files = fs.readdirSync(this.publishPath);
        const fileTypes = this.analyzeAllFileTypes(files);
        
        reportContent.push('📊 发布目录统计:');
        reportContent.push(`   总文件数: ${files.length}`);
        reportContent.push(`   FGUI包文件: ${fileTypes.xml} XML, ${fileTypes.bin} BIN`);
        reportContent.push(`   图片文件: ${fileTypes.png + fileTypes.jpg + fileTypes.jpeg}`);
        reportContent.push(`   Spine文件: ${fileTypes.atlas} .atlas, ${fileTypes.json} .json, ${fileTypes.skel} .skel`);
        reportContent.push(`   其他文件: ${fileTypes.other}`);
        reportContent.push(`   识别包数: ${this.foundPackages.length}`);
        reportContent.push('');

        // 识别到的包列表
        if (this.foundPackages.length > 0) {
            reportContent.push('📦 识别到的包:');
            this.foundPackages.forEach(pkg => {
                reportContent.push(`   ✅ ${pkg}`);
            });
            reportContent.push('');
        }

        // Spine 动画统计
        if (Object.keys(this.spineAnimations).length > 0) {
            reportContent.push('🎬 Spine 动画统计:');
            Object.keys(this.spineAnimations).forEach(animName => {
                const animFiles = this.spineAnimations[animName];
                reportContent.push(`   ${animName}: ${animFiles.length} 个文件`);
            });
            reportContent.push('');
        }

        // 图集检查结果
        if (this.oversizedAtlases.length > 0) {
            reportContent.push('🖼️  图集数量检查（超过2个2048图集）:');
            this.oversizedAtlases.forEach(atlasInfo => {
                reportContent.push(`   ❌ 包 "${atlasInfo.package}" 有 ${atlasInfo.atlasCount} 个图集`);
                
                // 列出所有图集
                atlasInfo.allAtlases.forEach(atlas => {
                    const sizeMB = (atlas.fileSize / (1024 * 1024)).toFixed(2);
                    const status = (atlas.width > 2048 || atlas.height > 2048) ? '❌' : '✅';
                    reportContent.push(`       ${status} ${atlas.filename}: ${atlas.size} (${sizeMB}MB)`);
                });
                reportContent.push('');
            });
            reportContent.push('');
        }

        // 输出错误
        if (this.errors.length > 0) {
            reportContent.push('❌ 错误:');
            this.errors.forEach(error => reportContent.push(`   ${error}`));
            reportContent.push('');
        }

        // 输出警告
        if (this.warnings.length > 0) {
            reportContent.push('⚠️  警告:');
            this.warnings.forEach(warning => reportContent.push(`   ${warning}`));
            reportContent.push('');
        }

        // 优化建议
        if (this.warnings.length > 0 || this.oversizedAtlases.length > 0) {
            reportContent.push('💡 优化建议:');
            
            if (this.oversizedAtlases.length > 0) {
                reportContent.push('   1. 图集数量过多的包，建议在FGUI编辑器中调整发布设置');
                reportContent.push('   2. 大尺寸图集考虑使用压缩格式或调整尺寸');
            }
            
            if (this.warnings.some(w => w.includes('Spine'))) {
                reportContent.push('   3. Spine动画文件不完整，请检查动画资源');
            }
            
            if (this.warnings.some(w => w.includes('缺少'))) {
                reportContent.push('   4. 缺少配对的XML/BIN文件，请检查发布设置');
            }
            
            reportContent.push('   5. 建议在FGUI编辑器中重新发布有问题的包');
            reportContent.push('');
        }

        // 总结
        reportContent.push('='.repeat(70));
        reportContent.push(`错误: ${this.errors.length}, 警告: ${this.warnings.length}`);
        reportContent.push(`识别包数: ${this.foundPackages.length}, 图集问题包: ${this.oversizedAtlases.length}`);
        reportContent.push(`Spine动画: ${Object.keys(this.spineAnimations).length} 个`);

        let conclusion = '';
        if (this.errors.length > 0) {
            conclusion = '❌ 检查失败，请修复错误！';
        } else if (this.warnings.length > 0 || this.oversizedAtlases.length > 0) {
            conclusion = '⚠️  检查完成，有优化建议需要注意';
        } else if (this.foundPackages.length === 0) {
            conclusion = '❌ 未识别到任何包，请检查发布目录';
        } else {
            conclusion = '✅ 所有检查通过！发布目录状态良好';
        }
        reportContent.push(conclusion);
        reportContent.push('='.repeat(70));

        // 输出到控制台和日志
        reportContent.forEach(line => {
            if (line.includes('❌')) {
                this.log(line.replace('❌ ', ''), 'error');
            } else if (line.includes('⚠️')) {
                this.log(line.replace('⚠️ ', ''), 'warning');
            } else if (line.includes('✅')) {
                this.log(line.replace('✅ ', ''), 'success');
            } else if (line.includes('📊') || line.includes('📦') || line.includes('🖼️') || line.includes('🎬') || line.includes('💡')) {
                console.log(line);
            } else if (line.startsWith('=')) {
                console.log(line);
            } else if (line.trim()) {
                console.log(line);
            }
        });

        const fullReport = reportContent.join('\n');
        fs.appendFileSync(this.logFile, '\n' + fullReport + '\n', 'utf8');

        return {
            errors: this.errors.length,
            warnings: this.warnings.length,
            foundPackages: this.foundPackages.length,
            oversizedAtlases: this.oversizedAtlases.length,
            spineAnimations: Object.keys(this.spineAnimations).length,
            logFile: this.logFile
        };
    }

    // 运行检查
    run() {
        this.log('🚀 开始 FGUI 发布检查 (支持 Spine 动画)...');
        this.log(`检查开始时间: ${new Date().toLocaleString()}`);
        
        if (!this.validatePublishStructure()) {
            this.generateReport();
            return;
        }

        // 执行检查
        this.findPackagesIntelligently(); // 智能识别包
        this.checkAtlases();              // 检查图集
        // this.checkSpineAnimations();      // 检查 Spine 动画
        // this.checkFileIntegrity();        // 检查文件完整性
        
        const result = this.generateReport();
        
        this.log(`检查完成时间: ${new Date().toLocaleString()}`);
        this.log(`详细报告已保存: ${result.logFile}`);
        
        if (result.errors > 0 || result.foundPackages === 0) {
            process.exit(1);
        } else {
            process.exit(0);
        }
    }
}

// 使用示例
if (require.main === module) {
    const publishPath = process.argv[2];
    const checker = new PublishedSpineChecker(publishPath);
    checker.run();
}

module.exports = PublishedSpineChecker;